﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.IO;
using SessionHunter.Business.Exceptions;
using SessionHunter.Model;

namespace SessionHunter.Business.SessionReading
{
    /// <summary>
    /// General helper class for functions related to reverse-engineering sessions
    /// </summary>
    public class SessionHelper
    {
        /// <summary>
        /// Occurs when a specific number of sessions have been processed
        /// </summary>
        public event EventHandler<SessionsProcessedArgs> SessionItemsProcessed;

        /// <summary>
        /// This will take the session data that was stored in the DB and break it down into
        /// individual items.
        /// </summary>
        /// <param name="logger">The logger.</param>
        /// <param name="sessionData">The session data.</param>
        /// <param name="sessionItems">A list of items in session.</param>
        /// <returns>
        /// True if we got sessions with no issue, or there were no sessions to retrieve.  False if there was an error.
        /// </returns>
        /// <remarks>
        /// This function uses knowledge from SessionMonitor-&gt;GetSessionItemCollections, but does not get static objects
        /// </remarks>
        public bool GetSessionItems(NLog.Logger logger, byte[] sessionData, out List<SessionItem> sessionItems)
        {
            Contract.Requires(logger != null);

            sessionItems = null;

            // If we have no data, just return null
            if (sessionData == null || sessionData.GetLength(0) == 0)
                return true;

            bool retVal = true;
            logger.Info("Called GetSessionItems");

            try
            {
                using (MemoryStream memoryStream = new MemoryStream(sessionData))
                {
                    // The session has a number of flags and then the actual data.  So we have to read it in exactly this order or it will break.
                    var reader = new BinaryReader(memoryStream);
                    reader.ReadInt32(); // This is the number of items
                    bool hasItems = reader.ReadBoolean(); // Flag on whether it has any items
                    bool hasStaticObjects = reader.ReadBoolean(); // Flag on whether it has static objects
                    if (hasItems)
                    {
                        // Called whenever sessions have been proccessed
                        var sessionsProcessed = new Action<int>((int sessionCount) =>
                        {
                            if (SessionItemsProcessed != null)
                                SessionItemsProcessed(this, new SessionsProcessedArgs(sessionCount));
                        });
                        retVal = SessionStateItemCollection_Custom.DeserializeToSessionItem(reader, sessionsProcessed, out sessionItems); // Now get the actual session items out
                    }

                    //TODO: Should we be looking at static objects here as well?  HttpStaticObjectsCollection.Deserialize(reader)
                }
            }
            catch (Exception ex)
            {
                throw new SessionApplicationException("Error trying to deserialize the session data", ex);
            }

            return retVal;
        }
    }
}
